package com.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.context.BaseContext;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Category;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.entity.Setmeal;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.exception.StatusStartOrStopExecption;
import com.sky.mapper.CategoryMapper;
import com.sky.mapper.DishFlavorMapper;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.PostConstruct;
import javax.imageio.stream.IIOByteBuffer;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class DishServiceImpl implements DishService {
    @Autowired
    private DishMapper dishMapper;

    @Autowired
    private SetmealMapper setmealMapper;

    @Autowired
    private DishFlavorMapper dishFlavorMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private CategoryMapper categoryMapper;

    /**
     * 预热所有可用菜品数据
     */
//    @PostConstruct
    public void initCacheData(){
        //1.查询所有可用菜品分类
        List<Category> categoryList = categoryMapper.queryCategoryList(1);
        if(CollectionUtils.isNotEmpty(categoryList)) {
            categoryList.forEach(c->{
                String key = "dish:" + c.getId();

                //2.清理之前缓存的数据
                stringRedisTemplate.delete(key);

                //3.查询各分类下所有可用菜品
                Dish dish = Dish.builder().categoryId(c.getId()).status(StatusConstant.ENABLE).build();
                List<Dish> dishList = dishMapper.list(dish);

                if(CollectionUtils.isNotEmpty(dishList)) {

                    //4.转为JSON列表
                    List<String> dishJSONList = dishList.stream().map(x -> {
                        //封装VO
                        DishVO dishVO = new DishVO();
                        BeanUtils.copyProperties(x, dishVO);

                        //根据菜品id查询对应的口味
                        List<DishFlavor> flavors = dishFlavorMapper.selectByDishId(x.getId());
                        if (CollectionUtils.isNotEmpty(flavors)) {
                            dishVO.setFlavors(flavors);
                        }
                        return JSON.toJSONString(dishVO);
                    }).collect(Collectors.toList());


                    //5.添加缓存
                    stringRedisTemplate.opsForList().leftPushAll(key,dishJSONList);

                    log.info("======================【缓存预热】缓存了菜品分类[{}-{}]的全部菜品数据======================",c.getId(), c.getName());
                }
            });
        }

    }

    /**
     * 新增菜品
     *
     * @param dto
     * @return
     */
    @Transactional
    @Override
    public Result addDish(DishDTO dto) {
        Dish dish = new Dish();
        //拷贝数据
        BeanUtils.copyProperties(dto, dish);
        //补全数据
        //通过AOP完成

        //插入菜品信息
        dishMapper.insert(dish);
        //插入口味信息
        DishFlavor dishFlavor = new DishFlavor();
        List<DishFlavor> flavors = dto.getFlavors();
        if (flavors != null && flavors.size() > 0) {
            for (DishFlavor flavor : flavors) {
//            dishFlavor.setDishId(dish.getId());
//            dishFlavor.setValue(flavor.getValue());
//            dishFlavor.setName(flavor.getName());
//            dishFlavorMapper.insert(dishFlavor);

                //给每个口味加上对应的菜品id
                flavor.setDishId(dish.getId());
            }
            dishFlavorMapper.insert(flavors);
                //清除缓存
                Long categoryId = dish.getCategoryId();
                String KEY = "dish:"+categoryId;
                redisTemplate.delete(KEY);

        }

        return Result.success();
    }

    /**
     * 条件分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public Result<PageResult> queryByPage(DishPageQueryDTO dto) {
        //开启分页，设置参数
        PageHelper.startPage(dto.getPage(), dto.getPageSize());

        Page<DishVO> dishes = dishMapper.select(dto);
        //封装数据
        PageResult pageResult = new PageResult();
        pageResult.setRecords(dishes);
        pageResult.setTotal(dishes.getTotal());
        return Result.success(pageResult);
    }

    /**
     * 删除操作
     *
     * @param ids
     * @return
     */
    @Override
    @Transactional
    public Result deleteByIds(List<Long> ids) {

        Integer count =0 ;
        //1.起售中的菜品不能删除
        // 1.1查询被删除的菜品中在售的数量，大于1不允许删除
        count = dishMapper.queryStatus(ids);
        if (count > 0) {
            throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
        }
        //2.被套餐包含的菜品不能删除
        count = setmealMapper.selectByDishIds(ids);
        if (count>0){
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }

        //清除缓存
        for (Long id : ids) {
            Dish dish = dishMapper.selectById(id);
            Long categoryId = dish.getCategoryId();
            String KEY = "dish:"+categoryId;
            redisTemplate.delete(KEY);
        }
        //3.删除菜品
        dishMapper.delete(ids);
        //删除菜品关联的口味
        dishFlavorMapper.deleteByDishId(ids);
        return Result.success();
    }

    /**
     * 根据id查询菜品
     *
     * @param id
     * @return
     */
    @Override
    public Result selectById(Long id) {
        //查询菜品
        Dish dish = dishMapper.selectById(id);
        //查询菜品对应的口味
        List<DishFlavor> dishFlavors = dishFlavorMapper.selectByDishId(id);
        //封装数据
        DishVO dishVO = new DishVO();
        BeanUtils.copyProperties(dish, dishVO);
        dishVO.setFlavors(dishFlavors);
        return Result.success(dishVO);
    }

    /**
     * 修改菜品信息
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional
    public Result updateDish(DishDTO dto) {
        //1.修改菜品信息
        Dish dish = new Dish();
        BeanUtils.copyProperties(dto, dish);
        //填充修改时间 AOP
        dishMapper.update(dish);
        //2.修改菜品口味
        List<DishFlavor> flavors = dto.getFlavors();
        for (DishFlavor flavor : flavors) {
            flavor.setDishId(dto.getId());
        }
        if (!flavors.isEmpty()) {
            // 2.1先删除口味
            ArrayList<Long> ids = new ArrayList<>();
            ids.add(dto.getId());
            dishFlavorMapper.deleteByDishId(ids);
            //2.2再添加口味
            dishFlavorMapper.insert(flavors);
        }

        //清除缓存
        Long categoryId = dish.getCategoryId();
        String KEY = "dish:"+categoryId;
        redisTemplate.delete(KEY);

        return Result.success();
    }

    /**
     * 根据分类id查询菜品
     *
     * @param id
     * @return
     */
    @Override
    public Result queryDishByCategoryId(Long id) {
        List<Dish> dishList = dishMapper.queryDishByCategoryId(id);
        return Result.success(dishList);
    }

    /**
     * 菜品起售停售
     *
     * @param status
     * @param id
     * @return
     */
    @Override
    public Result updateStatus(Integer status, Long id) {
        //停售菜品的同时也把相关联的套餐的套餐停售
        if (status==0){
            //先查询被哪些套餐关联了
            List<Long> setmealIds =  dishMapper.selectCountById(id);
            //停售这些套餐
            for (Long setmealId : setmealIds) {
                Setmeal build = Setmeal.builder()
                        .id(setmealId)
                        .status(status).build();
                setmealMapper.update(build);
            }
        }

        //停售菜品
        Dish dish = Dish.builder()
                .status(status)
                .id(id)
                .build();
        dishMapper.update(dish);
        //清除缓存
        Dish dish1 = dishMapper.selectById(id);
        Long categoryId = dish1.getCategoryId();
        String KEY = "dish:"+categoryId;
        redisTemplate.delete(KEY);
        return Result.success();
    }

    /**
     * 条件查询菜品和口味
     * @param dish
     * @return
     */
    public List<DishVO> listWithFlavor(Dish dish) { //根据分类id和状态查询
        //1.先从缓存中查询菜品
        String KEY = "dish:"+dish.getCategoryId();
        ListOperations<String, String> listOperations = stringRedisTemplate.opsForList();
        List<String> dishVOListString = listOperations.range(KEY, 0, -1);
        //把dishVO字符串集合转换成json对象 selectByDishId
        List<DishVO> dishVOList = dishVOListString.stream().map(x -> JSON.parseObject(x, DishVO.class)).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(dishVOList)){

            return dishVOList;
        }

        //2. 缓存无则查询表中菜品列表
        List<Dish> dishList = dishMapper.list(dish);
        if(CollectionUtils.isNotEmpty(dishList)){
            List<String> dishJsonList = dishList.stream().map(x->{
                DishVO dishVO = new DishVO();
                BeanUtils.copyProperties(x,dishVO);

                //根据菜品id查询对应的口味
                List<DishFlavor> flavors = dishFlavorMapper.selectByDishId(x.getId());
                if(CollectionUtils.isNotEmpty(flavors)) {
                    dishVO.setFlavors(flavors);
                }
                dishVOList.add(dishVO);
                return JSON.toJSONString(dishVO);
            }).collect(Collectors.toList());

            //3. 将表中查到的菜品列表添加到缓存中
            listOperations.leftPushAll(KEY,dishJsonList);
        }
        return dishVOList;
    }

}
